﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PH.Model.Accounts;
using PH.Model.Schools;
using PH.Model.Systems;
namespace PH.Data.Accounts
{
    public class UserCommand
    {
        public static void SaveCheck(UserModel user, DBCentre db)
        {
            if (string.IsNullOrEmpty(user.UserName))
                throw new Utils.PhException("请提供用户名");
            if (string.IsNullOrEmpty(user.RealName))
                throw new Utils.PhException("请提供姓名");
            if (string.IsNullOrEmpty(user.Email))
                throw new Utils.PhException("请提供Email");
            if (user.ID == 0)
            {
                if (string.IsNullOrEmpty(user.Password))
                    throw new Utils.PhException("请提供用户密码");
            }

            if (db != null)
            {
                if (db.DataContext.Users.Any(p=>p.UserName==user.UserName && p.Guid!=user.Guid))
                    throw new Utils.PhException("用户名重复，请重新选择一个用户名。");
                if (db.DataContext.Users.Any(p => p.Email == user.Email && p.Guid != user.Guid))
                    throw new Utils.PhException("Email重复，请重新选择一个Email。");
            }
        }

        public static UserModel CreateNewUser(UserModel user)
        {
            if (user != null)
            {
                user.CreatedOn = DateTime.Now;
                user.Guid = Guid.NewGuid();
                using (DBCentre db = new DBCentre())
                {
                    SaveCheck(user, db);
                    var dUser = Convertor.ConvertFrom<User, UserModel>(user);
                    db.DataContext.Users.Add(dUser);
                    db.DataContext.SaveChanges();
                    user.ID = dUser.ID;
                    return user;
                }
            }
            return null;
        }

        public static void UpdateUser(UserModel user)
        {
            if (user != null && user.Guid!=Guid.Empty)
            {
                using (DBCentre db = new DBCentre())
                {
                    var dUser = db.DataContext.Users.FirstOrDefault(p => p.Guid== user.Guid);
                    if (dUser != null)
                    {
                        user.ID = dUser.ID;
                        user.Password = dUser.Password; //保持密码不作修改
                        
                        SaveCheck(user, db);
                        Convertor.UpdateValue(user, dUser);
                        db.DataContext.SaveChanges();
                    }
                    else
                        throw new Utils.PhException("不存在的用户");
                }
            }
        }

        public static UserModel GetUser(Guid guid)
        {
            if (guid != Guid.Empty)
            {
                using (DBCentre db = new DBCentre())
                {
                    var dUser = db.DataContext.Users.FirstOrDefault(p => p.Guid == guid);
                    if (dUser != null)
                    {
                        var user = Convertor.ConvertTo<UserModel, User>(dUser);
                        user.Roles = Convertor.ConvertCollection<RoleModel, Role, RoleCollection>(dUser.Roles);
                        if (user.AssociatedSchoolID > 0)
                            user.School = Convertor.ConvertTo<SchoolModel, School>(dUser.School);
                        if (user.AssociatedStudentID > 0)
                            user.Student = Convertor.ConvertTo<StudentModel, Student>(dUser.Student);
                        if (user.AssociatedBureauID > 0)
                            user.Bureau = Convertor.ConvertTo<BureauModel, Bureau>(dUser.Bureau);
                        return user;
                    }
                }
            }
            return null;
        }
        public static UserModel GetUser(string username,bool getRoles=false)
        {
            if (!string.IsNullOrEmpty(username))
            {
                using (DBCentre db = new DBCentre())
                {
                    var dUser = db.DataContext.Users.FirstOrDefault(p => p.UserName == username);
                    if (dUser != null)
                    {
                        var user = Convertor.ConvertTo<UserModel, User>(dUser);
                        if (user != null)
                        {
                            if (getRoles)
                                user.Roles = Convertor.ConvertCollection<RoleModel, Role, RoleCollection>(dUser.Roles);
                        }
                        return user;
                    }
                }
            }
            return null;
        }
        public static UserModel GetUserByEmail(string email)
        {
            if (!string.IsNullOrEmpty(email))
            {
                using (DBCentre db = new DBCentre())
                {
                    var d = db.DataContext.Users.FirstOrDefault(p => p.Email == email);
                    if (d != null)
                    {
                        var ret = Convertor.ConvertTo<UserModel, User>(d);
                        return ret;
                    }
                }
            }
            return null;
        }
        public static UserModel GetUserByToken(Guid token)
        {
            if (token != Guid.Empty)
            {
                using (DBCentre db = new DBCentre())
                {
                    var ut = db.DataContext.UserTokens.FirstOrDefault(p => p.Token == token);
                    if (ut != null)
                    {
                        var dUser = db.DataContext.Users.FirstOrDefault(p => p.Guid == ut.UGuid);
                        if (dUser != null)
                        {
                            ut.UpdateTime = DateTime.Now;
                            db.DataContext.SaveChanges();
                            var user= Convertor.ConvertTo<UserModel, User>(dUser);
                            user.Roles = Convertor.ConvertCollection<RoleModel, Role, RoleCollection>(dUser.Roles);
                            if (user.AssociatedSchoolID > 0)
                                user.School = Convertor.ConvertTo<SchoolModel, School>(dUser.School);
                            if (user.AssociatedStudentID > 0)
                                user.Student = Convertor.ConvertTo<StudentModel, Student>(dUser.Student);
                            if (user.AssociatedBureauID > 0)
                                user.Bureau = Convertor.ConvertTo<BureauModel, Bureau>(dUser.Bureau);
                            return user;
                        }
                        else
                            throw new Utils.PhException("无效的用户");
                    }
                    else
                        throw new Utils.PhException("无效的Token");
                }
            }
            return null;
        }

        public static UserModel Login(string userName, string password)
        {
            using (DBCentre db = new DBCentre())
            {
                var dUser = db.DataContext.Users.FirstOrDefault(p => p.UserName == userName);
                if (dUser != null)
                {
                    #region 检测验证
                    if (dUser.Status != (int)Model.Status.Active) throw new Utils.PhException("帐号被禁用，请联系本单位的管理员");
                    if (dUser.Password.ToLower() != password.ToLower())
                    {
                        dUser.LoginTryTimes++;
                        db.DataContext.SaveChanges();
                        throw new Utils.PhException("用户名或密码错误");
                    }
                    #endregion

                    dUser.LastLoginTime = DateTime.Now;
                    dUser.LoginTryTimes = 0;
                    db.DataContext.SaveChanges();
                    var ret = Convertor.ConvertTo<UserModel, User>(dUser);
                    ret.Roles = Convertor.ConvertCollection<RoleModel, Role, RoleCollection>(dUser.Roles);
                    if (ret.AssociatedSchoolID > 0)
                        ret.School = Convertor.ConvertTo<SchoolModel, School>(dUser.School);
                    if (ret.AssociatedStudentID > 0)
                        ret.Student = Convertor.ConvertTo<StudentModel, Student>(dUser.Student);
                    if (ret.AssociatedBureauID > 0)
                        ret.Bureau = Convertor.ConvertTo<BureauModel, Bureau>(dUser.Bureau);
                    return ret;
                }
                else
                    throw new Utils.PhException("用户名或密码错误");
            }
        }

        public static void RequestPasswordModify(Guid guid)
        {
            if (guid != Guid.Empty)
            {
                using (DBCentre db = new DBCentre())
                {
                    var dUser = db.DataContext.Users.FirstOrDefault(p => p.Guid == guid);
                    if (dUser != null)
                    {
                        dUser.ResetPasswordExpired = DateTime.Now.AddHours(5);
                        db.DataContext.SaveChanges();
                    }
                }
            }
        }

        public static bool ResetPassword(Guid guid,string newPassword)
        {
            if (guid != Guid.Empty)
            {
                using (DBCentre db = new DBCentre())
                {
                    var dUser = db.DataContext.Users.FirstOrDefault(p => p.Guid == guid);
                    if (dUser != null)
                    {
                        if (dUser.ResetPasswordExpired != null && dUser.ResetPasswordExpired.Value.CompareTo(DateTime.Now) >= 0)
                        {
                            dUser.Password = newPassword;
                            dUser.ResetPasswordExpired = null;
                            db.DataContext.SaveChanges();
                            return true;
                        }else
                            throw new Utils.PhException("此链接已经失效。");
                    }
                    else
                        throw new Utils.PhException("此用户不存在");
                }
            }
            return false;
        }

        public static void ChangeEmail(Guid guid, string email)
        {
            if (guid == Guid.Empty) return;
            if (!Utils.Email.IsEmail(email)) throw new Utils.PhException("请提供正确的Email。");
            using (DBCentre db = new DBCentre())
            {
                var duser = db.DataContext.Users.FirstOrDefault(p => p.Guid == guid);
                if (duser != null)
                {
                    if (db.DataContext.Users.Any(p => p.Email == email))
                        throw new Utils.PhException("Email重复，请重新选择一个Email。");

                    duser.Email = email;
                    db.DataContext.SaveChanges();
                }else
                    throw new Utils.PhException("无此用户");
            }
        }

        #region membership

        public static UserCollection FindUsersInRole(string roleName, string usernameToMatch)
        {
            UserCollection results = new UserCollection();
            using (DBCentre db = new DBCentre())
            {
                IQueryable<User> q = db.DataContext.Users;
                q = q.Where(p => p.UserName.Equals(usernameToMatch, StringComparison.CurrentCultureIgnoreCase));
                q = q.Where(p => p.Roles.Any(o => o.RoleName == roleName));
                var n = q.Count();
                if (n > 0)
                {
                    var lst = q.ToList();
                    results = Convertor.ConvertCollection<UserModel, User, UserCollection>(lst);
                    results.TotalRecordsCount = n;
                }
            }
            return results;
        }

        public static UserCollection GetUsersInRole(string roleName)
        {
            UserCollection results = new UserCollection();
            using (DBCentre dbCentre = new DBCentre())
            {
                IQueryable<User> q = dbCentre.DataContext.Users;
                q = q.Where(p => p.Roles.Any(o => o.RoleName == roleName));
                var n = q.Count();
                if (n > 0)
                {
                    var lst = q.ToList();
                    results = Convertor.ConvertCollection<UserModel, User, UserCollection>(lst);
                    results.TotalRecordsCount = n;
                }
            }
            return results;
        }

        public static bool ChangePassword(string userName, string oldPassword, string newPassword)
        {
            if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(oldPassword) && !string.IsNullOrEmpty(newPassword))
            {
                using (DBCentre db = new DBCentre())
                {
                    var dUser = db.DataContext.Users.FirstOrDefault(p => p.UserName == userName);
                    if (dUser != null && dUser.Password.ToLower() == oldPassword.ToLower())
                    {
                        dUser.Password = newPassword;
                        db.DataContext.SaveChanges();
                        return true;
                    }
                    else
                        throw new Utils.PhException("旧密码不正确");
                }
            }
            return false;
        }

        public static bool IsUserInRole(string username, string roleName)
        {
            bool result = false;
            using (DBCentre db = new DBCentre())
            {
                result = db.DataContext.Users.Any(p => p.UserName == username && p.Roles.Any(o => o.RoleName == roleName));
            }
            return result;
        }

        public static void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            if (usernames != null && roleNames != null)
            {
                using (DBCentre db = new DBCentre())
                {
                    var roles = db.DataContext.Roles.Where(p => roleNames.Contains(p.RoleName)).ToList();
                    roles.RemoveAll(p => p.Users.Any(o => usernames.Contains(o.UserName)));
                    db.DataContext.SaveChanges();
                }
            }
        }
        #endregion
    }
}
